AWS Lambda PowertoolsのMetrics Utilityを使ってカスタムメトリクスを作成してみた

AWS Lambda PowertoolsのMetrics Utilityを使ってカスタムメトリクスを作成してみた

Lambdaでカスタムメトリクスを作成するようなものはLambda PowertoolsのMetrics Utilityを使ってみよう
Clock Icon2024.11.25

PutMetricData API実行にかかる時間とスロットリングが気になる

こんにちは、のんピ(@non____97)です。

皆さんはCloudWatchのPutMetricData API実行にかかる時間とスロットリングが気になったことはありますか? 私はあります。

以下記事でSnapMirror relationshipの状態をPutMetricDataするVPC Lambdaを定期実行する方法を紹介しました。

https://dev.classmethod.jp/articles/amazon-fsx-for-netapp-ontap-snapmirror-health-cloudwatch-metrics/

こちらの記事で紹介しているとおり、PutMetricData APIを叩くタイミングで700msほど時間がかかっています。そのため、カスタムメトリクスが多くなればなるほどPutMetricDataにかかる時間が多くなり、タイムアウトする可能性が高いです。

また、PutMetricDataは150 TPSというレートリミットもあり、都度PutMetricDataを叩くのは得策ではありません。

**注意:**ほとんどの API コールでは、1 秒あたりに実行される API コールの数に制限があります。これは 1 秒あたりのトランザクション数 (TPS) として測定されます。PutMetricData の場合、制限は 150 TPS です。

Amazon CloudWatch を使用して AWS API コールの使用量をモニタリングする | AWS re:Post

レートリミットの対策としては、以下コードのように、カスタムメトリクスごとにPutMetricDataを叩いていた処理をある程度の数でまとめて、数回のPutMetricDataに分割して叩くことが挙げられます。これにより実行時間も抑えることが可能になります。

https://github.com/non-97/monitoring-snapmirror-relationship-health/blob/v1.1.0/lib/src/lambda/handler/index.py

メトリクスを一つの変数にまとめるロジックを書いたりするのは面倒です。

そんなときに役立つのがAWS Lambda PowertoolsのMetrics Utilityです。

Lambda Powertoolsの説明は以下builders.flashや、Lambda Powertoolsのホームサイトが参考になります。

https://aws.amazon.com/jp/builders-flash/202207/lambda-powertools-python-4/

https://docs.powertools.aws.dev/lambda/python/latest/

https://pages.awscloud.com/rs/112-TZM-766/images/20221124_24th_ISV_DiveDeepSeminar_Lambda_Powertools.pdf

Metrics UtilityはAmazon CloudWatch Embedded Metric Format (EMF)を用いて、CloudWatch Logsに出力されたログをベースにカスタムメトリクスを作成します。PutMetricData APIを叩く訳ではないため、PutMetricData にかかる時間とスロットリングから解放されます。

また、Lambda関数はCloudWatch Logsのエンドポイントが存在しなくともCloudWatch Logsにログ出力することが可能です。そのため、上述の記事で作成していたCloudWatchのVPCエンドポイントも不要になります。

AWS Lambda Powertoolsに関連する記事はいくつかありますが、Metrics Utilityを実際に行なっているものはありませんでした。

https://dev.classmethod.jp/tags/lambda-powertools/

実際に試してみます。

使用するコードの構成

Lambda関数

用意したコードは以下GitHubリポジトリに保存しています。

https://github.com/non-97/monitoring-snapmirror-relationship-health/tree/v2.0.0

まず、Metrics Utilityを使用している部分を抜粋して紹介します。

Metrics Utilityを使用する場合、aws_lambda_powertoolsからMetricsをインポートしてインスタンス化します。そして、metrics.log_metricsデコレーターをLambda関数のハンドラーに指定します。

.
.
(中略)
.
.
from aws_lambda_powertools import Logger, Tracer, Metrics, single_metric
from aws_lambda_powertools.metrics import MetricUnit
.
.
(中略)
.
.
# Lambda Powertoolsの設定
logger = Logger()
tracer = Tracer()
metrics = Metrics()
.
.
(中略)
.
.
# SnapMirror relationshipの個別のHealthをメトリクスとして整理
def process_individual_relationship_metrics(relationship: Dict[str, Any]) -> None:
    # HealthがTrueの場合は1
    # HealthがFalseの場合は0
    health_value = 1 if relationship.get("healthy", False) else 0
    with single_metric(
        name="SnapMirrorRelationshipHealth",
        unit=MetricUnit.Count,
        value=health_value,
    ) as metric:
        metric.add_dimension(
            "SourcePath", relationship.get("source", {}).get("path", "Unknown")
        )
        metric.add_dimension(
            "DestinationPath",
            relationship.get("destination", {}).get("path", "Unknown"),
        )
        metric.add_dimension("RelationshipUUID", relationship.get("uuid", "Unknown"))

# Destination SVM 単位のHealthをメトリクスとして整理
def process_svm_level_metrics(svm_health: Dict[str, Dict[str, Any]]) -> None:
    # Destination SVM 単位で、全てのSnapMirror relationshipのHealthがTrueの場合は1
    # Destination SVM 単位で、いずれかのSnapMirror relationshipのHealthがFalseの場合は0
    for svm_uuid, svm_info in svm_health.items():
        with single_metric(
            name="SnapMirrorRelationshipHealth",
            unit=MetricUnit.Count,
            value=1 if svm_info["healthy"] else 0,
        ) as metric:
            metric.add_dimension(
                "DestinationStorageVirtualMachineName", svm_info["name"]
            )
            metric.add_dimension("DestinationStorageVirtualMachineUUID", svm_uuid)
.
.
(中略)
.
.
@metrics.log_metrics()
@logger.inject_lambda_context()
@tracer.capture_lambda_handler
def lambda_handler(event: dict, context: LambdaContext) -> None:
    main()

Metrics Utilityのサンプルとしてよく見るのがmetrics.add_metric()metrics.add_dimension()を使うパターンです。

今回のケースに当てはめると以下のとおりです。

# SnapMirror relationshipの個別のHealthをメトリクスとして整理
def process_individual_relationship_metrics(relationship: Dict[str, Any]) -> None:
    # HealthがTrueの場合は1
    # HealthがFalseの場合は0
    health_value = 1 if relationship.get("healthy", False) else 0

    metrics.add_metric(
        name="SnapMirrorRelationshipHealth",
        unit=MetricUnit.Count,
        value=health_value,
    )
    metrics.add_dimension(
        "SourcePath", relationship.get("source", {}).get("path", "Unknown")
    )
    metrics.add_dimension(
        "DestinationPath", relationship.get("destination", {}).get("path", "Unknown")
    )
    metrics.add_dimension("RelationshipUUID", relationship.get("uuid", "Unknown"))

# Destination SVM 単位のHealthをメトリクスとして整理
def process_svm_level_metrics(svm_health: Dict[str, Dict[str, Any]]) -> None:
    # Destination SVM 単位で、全てのSnapMirror relationshipのHealthがTrueの場合は1
    # Destination SVM 単位で、いずれかのSnapMirror relationshipのHealthがFalseの場合は0
    for svm_uuid, svm_info in svm_health.items():
        metrics.add_metric(
            name="SnapMirrorRelationshipHealth",
            unit=MetricUnit.Count,
            value=1 if svm_info["healthy"] else 0,
        )
        metrics.add_dimension("DestinationStorageVirtualMachineName", svm_info["name"])
        metrics.add_dimension("DestinationStorageVirtualMachineUUID", svm_uuid)

しかし、今回のケースでは、このような書き方はマッチしていません。

add_dimension()は集約するメトリクス全てのディメンションとして設定されます。そのため、上述の場合は以下のようなログが出力されます。

{
    "_aws": {
        "Timestamp": 1732455268754,
        "CloudWatchMetrics": [
            {
                "Namespace": "ONTAP/SnapMirror",
                "Dimensions": [
                    [
                        "SourcePath",
                        "DestinationPath",
                        "RelationshipUUID",
                        "DestinationStorageVirtualMachineName",
                        "DestinationStorageVirtualMachineUUID",
                        "service"
                    ]
                ],
                "Metrics": [
                    {
                        "Name": "SnapMirrorRelationshipHealth",
                        "Unit": "Count"
                    }
                ]
            }
        ]
    },
    "SourcePath": "svm:vol_ntfs",
    "DestinationPath": "svm:vol_ntfs_dst",
    "RelationshipUUID": "8a6d0455-9b21-11ef-accd-b31c82a68aa5",
    "DestinationStorageVirtualMachineName": "svm2",
    "DestinationStorageVirtualMachineUUID": "2bb6c4fc-a554-11ef-accd-b31c82a68aa5",
    "service": "monitoring-snapmirror-relationship-health",
    "SnapMirrorRelationshipHealth": [
        1,
        1,
        0,
        0,
        1
    ]
}

今回はディメンションのキー及び値はPUTしたいメトリクスごとに異なります。

このような場合はsingle_metric()を用いて、都度シリアライズしてCloudWatch Logsに出力するようにします。

single_metric()の引数は以下ドキュメントが参考になります。

https://docs.powertools.aws.dev/lambda/python/latest/api/metrics/index.html#aws_lambda_powertools.metrics.single_metric

実際に出力されるログは以下のとおりです。

{
    "_aws": {
        "Timestamp": 1732494357690,
        "CloudWatchMetrics": [
            {
                "Namespace": "ONTAP/SnapMirror",
                "Dimensions": [
                    [
                        "SourcePath",
                        "DestinationPath",
                        "RelationshipUUID",
                        "service"
                    ]
                ],
                "Metrics": [
                    {
                        "Name": "SnapMirrorRelationshipHealth",
                        "Unit": "Count"
                    }
                ]
            }
        ]
    },
    "SourcePath": "svm:vol_ntfs",
    "DestinationPath": "svm:vol_ntfs_dst",
    "RelationshipUUID": "8a6d0455-9b21-11ef-accd-b31c82a68aa5",
    "service": "monitoring-snapmirror-relationship-health",
    "SnapMirrorRelationshipHealth": [
        0
    ]
}

{
    "_aws": {
        "Timestamp": 1732494357690,
        "CloudWatchMetrics": [
            {
                "Namespace": "ONTAP/SnapMirror",
                "Dimensions": [
                    [
                        "DestinationStorageVirtualMachineName",
                        "DestinationStorageVirtualMachineUUID",
                        "service"
                    ]
                ],
                "Metrics": [
                    {
                        "Name": "SnapMirrorRelationshipHealth",
                        "Unit": "Count"
                    }
                ]
            }
        ]
    },
    "DestinationStorageVirtualMachineName": "svm",
    "DestinationStorageVirtualMachineUUID": "3ba0f5ee-6064-11ef-a92a-512f30fadf39",
    "service": "monitoring-snapmirror-relationship-health",
    "SnapMirrorRelationshipHealth": [
        0
    ]
}

その他前回の記事から変更した内容は以下のとおりです。

  • aws_xray_sdkではなく、Lambda PowertoolsのTracer Utilityを使用するよう変更
  • 標準のLoggerではなく、Lambda PowertoolsのLogger Utilityを使用するよう変更
    • SnapMirror relationshipの情報を構造化されたログとして出力
  • AWS Parameter and Secrets Lambda extension ではなく、Lambda PowertoolsのParameters Utilityを使用するよう変更

AWS CDK

AWS CDK側は大きく変更していません。

Lambda関数周りだと、Lambda PowertoolsのLambda Layerを指定してLambda関数にアタッチしたことと、AWS Parameter and Secrets Lambda extensionのLambda Layerをデタッチしたこと程度です。

/lib/construct/lambda-construct.ts
    const lambdaPowertoolsLayer =
      cdk.aws_lambda.LayerVersion.fromLayerVersionArn(
        this,
        "lambdaPowertoolsLayer",
        `arn:aws:lambda:${
          cdk.Stack.of(this).region
        }:017000801446:layer:AWSLambdaPowertoolsPythonV3-python313-arm64:4`
      );

    // Lambda Function
    const lambdaFunction = new cdk.aws_lambda.Function(this, "Default", {
      runtime: cdk.aws_lambda.Runtime.PYTHON_3_13,
      handler: "index.lambda_handler",
      code: cdk.aws_lambda.Code.fromAsset(
        path.join(__dirname, "../src/lambda/handler")
      ),
      role,
      vpc,
      vpcSubnets: vpc.selectSubnets(props.functionSubnetSelection),
      securityGroups: [securityGroup],
      architecture: cdk.aws_lambda.Architecture.ARM_64,
      timeout: cdk.Duration.seconds(20),
      tracing: cdk.aws_lambda.Tracing.ACTIVE,
      logRetention: cdk.aws_logs.RetentionDays.ONE_MONTH,
      loggingFormat: cdk.aws_lambda.LoggingFormat.JSON,
      applicationLogLevelV2: props.functionApplicationLogLevel,
      systemLogLevelV2: props.functionSystemLogLevel,
      layers: [layer, lambdaPowertoolsLayer],
      environment: {
        POWERTOOLS_LOG_LEVEL: props.powertoolsLogLevel || "INFO",
        POWERTOOLS_SERVICE_NAME: "monitoring-snapmirror-relationship-health",
        POWERTOOLS_METRICS_NAMESPACE: "ONTAP/SnapMirror",
        POWERTOOLS_PARAMETERS_MAX_AGE: "500",
        FSXN_DNS_NAME: props.fsxnDnsName,
        FSXN_USER_NAME: props.fsxnUserName,
        FSXN_USER_CREDENTIAL_SSM_PARAMETER_STORE_NAME:
          props.fsxnUserCredentialSsmParameterStoreName,
      },
    });

Lambda PowertoolsのLambda LayerのARNは以下のとおりです。

Architecture Layer ARN
x86_64 arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-{python_version}-x86_64:4
ARM arn:aws:lambda:{region}:017000801446:layer:AWSLambdaPowertoolsPythonV3-{python_version}-arm64:4

抜粋 : Homepage - Powertools for AWS Lambda (Python)

リージョンとPythonのバージョンだけ環境に合わせて修正してあげましょう。

また、PutMetricData APIを叩く必要がなくなったため、CloudWatchのVPCエンドポイントを作成する処理を削除しました。

やってみた

検証環境

検証環境は以下のとおりです。

AWS Lambda PowertoolsのMetrics Utilityを使ってカスタムメトリクスを作成してみた検証環境構成図.png

CloudWatch Logsを確認する

AWS CDKで各種リソースデプロイ後、しばらく放置します。

その後Lambda関数が出力したログをCloudWatch Logsから確認します。

以下はコールドスタート時のログです。

{
    "time": "2024-11-25T00:25:48.585Z",
    "type": "platform.initStart",
    "record": {
        "initializationType": "on-demand",
        "phase": "init",
        "runtimeVersion": "python:3.13.v13",
        "runtimeVersionArn": "arn:aws:lambda:us-east-1::runtime:fc029c719040917900a389eb355c0478fa0ca5f4f71b29f54c05f14fc48f9b7c",
        "functionName": "MonitoringSnapmirrorRelati-LambdaConstruct4CD6E168-oSwLvY2NYrX7",
        "functionVersion": "$LATEST"
    }
}
{
    "timestamp": "2024-11-25T00:25:53Z",
    "level": "INFO",
    "message": "successfully patched module botocore",
    "logger": "aws_xray_sdk.core.patcher",
    "requestId": ""
}

{
    "timestamp": "2024-11-25T00:25:53Z",
    "level": "INFO",
    "message": "successfully patched module sqlite3",
    "logger": "aws_xray_sdk.core.patcher",
    "requestId": ""
}

{
    "timestamp": "2024-11-25T00:25:53Z",
    "level": "INFO",
    "message": "successfully patched module requests",
    "logger": "aws_xray_sdk.core.patcher",
    "requestId": ""
}

{
    "timestamp": "2024-11-25T00:25:53Z",
    "level": "INFO",
    "message": "Found credentials in environment variables.",
    "logger": "botocore.credentials",
    "requestId": ""
}

{
    "time": "2024-11-25T00:25:54.111Z",
    "type": "platform.start",
    "record": {
        "requestId": "c2bc8509-e116-4c0b-b750-235b412f8a76",
        "version": "$LATEST",
        "tracing": {
            "spanId": "02e981a9673a1a60",
            "type": "X-Amzn-Trace-Id",
            "value": "Root=1-6743c40c-0817968e2fea27db7a9524f1;Parent=6a897cd92b74ca11;Sampled=1"
        }
    }
}
{
    "timestamp": "2024-11-25T00:25:54Z",
    "level": "INFO",
    "message": "Found credentials in environment variables.",
    "logger": "botocore.credentials",
    "requestId": "c2bc8509-e116-4c0b-b750-235b412f8a76"
}

{
    "_aws": {
        "Timestamp": 1732494357414,
        "CloudWatchMetrics": [
            {
                "Namespace": "ONTAP/SnapMirror",
                "Dimensions": [
                    [
                        "SourcePath",
                        "DestinationPath",
                        "RelationshipUUID",
                        "service"
                    ]
                ],
                "Metrics": [
                    {
                        "Name": "SnapMirrorRelationshipHealth",
                        "Unit": "Count"
                    }
                ]
            }
        ]
    },
    "SourcePath": "svm:vol_ntfs_dst",
    "DestinationPath": "svm:vol_ntfs",
    "RelationshipUUID": "1d16800a-9b2e-11ef-accd-b31c82a68aa5",
    "service": "monitoring-snapmirror-relationship-health",
    "SnapMirrorRelationshipHealth": [
        1
    ]
}

{
    "_aws": {
        "Timestamp": 1732494357552,
        "CloudWatchMetrics": [
            {
                "Namespace": "ONTAP/SnapMirror",
                "Dimensions": [
                    [
                        "SourcePath",
                        "DestinationPath",
                        "RelationshipUUID",
                        "service"
                    ]
                ],
                "Metrics": [
                    {
                        "Name": "SnapMirrorRelationshipHealth",
                        "Unit": "Count"
                    }
                ]
            }
        ]
    },
    "SourcePath": "svm:vol_ntfs_dst",
    "DestinationPath": "svm2:vol_ntfs_dst_dst",
    "RelationshipUUID": "2c64d414-a556-11ef-accd-b31c82a68aa5",
    "service": "monitoring-snapmirror-relationship-health",
    "SnapMirrorRelationshipHealth": [
        1
    ]
}

{
    "_aws": {
        "Timestamp": 1732494357690,
        "CloudWatchMetrics": [
            {
                "Namespace": "ONTAP/SnapMirror",
                "Dimensions": [
                    [
                        "SourcePath",
                        "DestinationPath",
                        "RelationshipUUID",
                        "service"
                    ]
                ],
                "Metrics": [
                    {
                        "Name": "SnapMirrorRelationshipHealth",
                        "Unit": "Count"
                    }
                ]
            }
        ]
    },
    "SourcePath": "svm:vol_ntfs",
    "DestinationPath": "svm:vol_ntfs_dst",
    "RelationshipUUID": "8a6d0455-9b21-11ef-accd-b31c82a68aa5",
    "service": "monitoring-snapmirror-relationship-health",
    "SnapMirrorRelationshipHealth": [
        0
    ]
}

{
    "_aws": {
        "Timestamp": 1732494357690,
        "CloudWatchMetrics": [
            {
                "Namespace": "ONTAP/SnapMirror",
                "Dimensions": [
                    [
                        "DestinationStorageVirtualMachineName",
                        "DestinationStorageVirtualMachineUUID",
                        "service"
                    ]
                ],
                "Metrics": [
                    {
                        "Name": "SnapMirrorRelationshipHealth",
                        "Unit": "Count"
                    }
                ]
            }
        ]
    },
    "DestinationStorageVirtualMachineName": "svm",
    "DestinationStorageVirtualMachineUUID": "3ba0f5ee-6064-11ef-a92a-512f30fadf39",
    "service": "monitoring-snapmirror-relationship-health",
    "SnapMirrorRelationshipHealth": [
        0
    ]
}

{
    "level": "INFO",
    "location": "log_unhealthy_relationship:166",
    "message": "Unhealthy SnapMirror Relationship detected",
    "timestamp": "2024-11-25 00:25:57,690+0000",
    "service": "monitoring-snapmirror-relationship-health",
    "cold_start": true,
    "function_name": "MonitoringSnapmirrorRelati-LambdaConstruct4CD6E168-oSwLvY2NYrX7",
    "function_memory_size": "128",
    "function_arn": "arn:aws:lambda:us-east-1:<AWSアカウントID>:function:MonitoringSnapmirrorRelati-LambdaConstruct4CD6E168-oSwLvY2NYrX7",
    "function_request_id": "c2bc8509-e116-4c0b-b750-235b412f8a76",
    "relationship": {
        "state": "broken_off",
        "unhealthy_reason": [
            {
                "code": "13303943",
                "message": "SnapMirror relationship is unhealthy. Reason: Scheduled update failed to start. (Destination svm:vol_ntfs_dst must be a data-protection volume.)."
            }
        ],
        "uuid": "8a6d0455-9b21-11ef-accd-b31c82a68aa5",
        "source_path": "svm:vol_ntfs",
        "destination_path": "svm:vol_ntfs_dst"
    },
    "xray_trace_id": "1-6743c40c-0817968e2fea27db7a9524f1"
}

{
    "_aws": {
        "Timestamp": 1732494357691,
        "CloudWatchMetrics": [
            {
                "Namespace": "ONTAP/SnapMirror",
                "Dimensions": [
                    [
                        "DestinationStorageVirtualMachineName",
                        "DestinationStorageVirtualMachineUUID",
                        "service"
                    ]
                ],
                "Metrics": [
                    {
                        "Name": "SnapMirrorRelationshipHealth",
                        "Unit": "Count"
                    }
                ]
            }
        ]
    },
    "DestinationStorageVirtualMachineName": "svm2",
    "DestinationStorageVirtualMachineUUID": "2bb6c4fc-a554-11ef-accd-b31c82a68aa5",
    "service": "monitoring-snapmirror-relationship-health",
    "SnapMirrorRelationshipHealth": [
        1
    ]
}

/opt/python/aws_lambda_powertools/metrics/provider/base.py:211: UserWarning: No application metrics to publish. The cold-start metric may be published if enabled. If application metrics should never be empty, consider using 'raise_on_empty_metrics'
self.flush_metrics(raise_on_empty_metrics=raise_on_empty_metrics)
{
    "time": "2024-11-25T00:25:57.769Z",
    "type": "platform.report",
    "record": {
        "requestId": "c2bc8509-e116-4c0b-b750-235b412f8a76",
        "metrics": {
            "durationMs": 3656.895,
            "billedDurationMs": 3657,
            "memorySizeMB": 128,
            "maxMemoryUsedMB": 123,
            "initDurationMs": 5524.48
        },
        "tracing": {
            "spanId": "02e981a9673a1a60",
            "type": "X-Amzn-Trace-Id",
            "value": "Root=1-6743c40c-0817968e2fea27db7a9524f1;Parent=6a897cd92b74ca11;Sampled=1"
        },
        "status": "success"
    }
}

Unhealthy SnapMirror Relationship detectedとして出力されるSnapMirror relationshipのログが構造的で非常に分かりやすいですね。CloudWatch Logs Insightで検索するときにも役立ちそうです。行番号も

また、DEBUGの場合は、正常なSnapMirror relationshipを含めて全ての情報を出力するようにしています。実際のログは以下のとおりです。

{
    "level": "DEBUG",
    "location": "evaluate_and_report_snapmirror_health:225",
    "message": "SnapMirror Relationship detected",
    "timestamp": "2024-11-24 09:46:46,278+0000",
    "service": "monitoring-snapmirror-relationship-health",
    "cold_start": false,
    "function_name": "MonitoringSnapmirrorRelati-LambdaConstruct4CD6E168-oSwLvY2NYrX7",
    "function_memory_size": "128",
    "function_arn": "arn:aws:lambda:us-east-1:<AWSアカウントID>:function:MonitoringSnapmirrorRelati-LambdaConstruct4CD6E168-oSwLvY2NYrX7",
    "function_request_id": "b76742f5-d82f-4ead-b2fc-2037d8eb5dbd",
    "relationship": {
        "_links": {
            "self": {
                "href": "/api/snapmirror/relationships/8a6d0455-9b21-11ef-accd-b31c82a68aa5/"
            }
        },
        "backoff_level": "high",
        "destination": {
            "path": "svm:vol_ntfs_dst",
            "svm": {
                "_links": {
                    "self": {
                        "href": "/api/svm/svms/3ba0f5ee-6064-11ef-a92a-512f30fadf39"
                    }
                },
                "name": "svm",
                "uuid": "3ba0f5ee-6064-11ef-a92a-512f30fadf39"
            }
        },
        "group_type": "none",
        "healthy": false,
        "last_transfer_network_compression_ratio": "1:1",
        "last_transfer_type": "update",
        "policy": {
            "_links": {
                "self": {
                    "href": "/api/snapmirror/policies/10dca2b7-6063-11ef-a92a-512f30fadf39"
                }
            },
            "name": "MirrorAllSnapshots",
            "type": "async",
            "uuid": "10dca2b7-6063-11ef-a92a-512f30fadf39"
        },
        "restore": false,
        "source": {
            "path": "svm:vol_ntfs",
            "svm": {
                "_links": {
                    "self": {
                        "href": "/api/svm/svms/3ba0f5ee-6064-11ef-a92a-512f30fadf39"
                    }
                },
                "name": "svm",
                "uuid": "3ba0f5ee-6064-11ef-a92a-512f30fadf39"
            }
        },
        "state": "broken_off",
        "throttle": 0,
        "total_transfer_bytes": 44409681004,
        "total_transfer_duration": "PT8M49S",
        "transfer": {
            "bytes_transferred": 7120,
            "end_time": "2024-11-05T04:15:06+00:00",
            "state": "success",
            "total_duration": "PT4S"
        },
        "transfer_schedule": {
            "_links": {
                "self": {
                    "href": "/api/cluster/schedules/0914a37a-6063-11ef-a92a-512f30fadf39"
                }
            },
            "name": "5min",
            "uuid": "0914a37a-6063-11ef-a92a-512f30fadf39"
        },
        "unhealthy_reason": [
            {
                "code": "13303943",
                "message": "SnapMirror relationship is unhealthy. Reason: Scheduled update failed to start. (Destination svm:vol_ntfs_dst must be a data-protection volume.)."
            }
        ],
        "uuid": "8a6d0455-9b21-11ef-accd-b31c82a68aa5"
    },
    "xray_trace_id": "1-6742f605-660aed4c42020cb173919028"
}

CloudWatchメトリクスを確認する

CloudWatchのコンソールからカスタムメトリクスを確認します。

7.カスタムメトリクスとして扱われていることを確認1.png

8.カスタムメトリクスとして扱われていることを確認2.png

いずれのディメンションのメトリクスでも意図したとおり、作成されていますね。

X-Rayのトレース結果を確認する

X-Rayのトレース結果も確認します。

6.おおよそ2秒未満.png

26回ほど実行してほとんどの実行時間が2秒未満です。前回の記事では2秒を超えているものがほとんどだったので実行時間が短くなったことが分かります。

また、コールドスタート時も前回記事の場合は14秒ほどかかっていたものが10秒弱と非常に速くなりました。

AWS Parameter and Secrets Lambda extensionの場合はSSM Parameter Storeにアクセスする際に時折失敗することもあり、3秒強かかっていました。

1.AWS-Parameters-and-Secrets-Lambda-Extensionを使用した場合.png

こちらが2秒弱と1秒以上短くなっています。

9.1.73秒に短縮.png

なお、認証情報を扱う場合、Tracer Utilitiesによって認証情報が記録されないようにケアする必要があります。

何もケアしない場合、以下のようにFSxNファイルシステムで使用するパスワードが見えてしまっています。

3.パスワードが表示されてしまう.png

こちらを避ける場合は、該当の関数に@tracer.capture_method(capture_response=False)デコレーターを付与し、レスポンスの自動キャプチャを無効にします。

付与した後に再実行したLambda関数のトレース結果を確認すると、確かに同じセグメントでもメタデータに認証情報が含まれません。

4.パスワードが表示されなくなった.png

Lambdaでカスタムメトリクスを作成するようなものはLambda PowertoolsのMetrics Utilityを使ってみよう

AWS Lambda PowertoolsのMetrics Utilityを使ってカスタムメトリクスを作成してみました。

今回のケースのように、標準メトリクスでないメトリクスを収集するために、VPC Lambdaを定期実行するような場合は、Lambda PowertoolsのMetrics Utilityを使うとランニングコスト的にも実装コスト的にもメリットがありそうです。

この記事が誰かの助けになれば幸いです。

以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.